/*
 * File:		I2C.c
 * Purpose:		I2C transfer functions and interrupt handler
 *
 * Notes:		
 *  
 */
#define I2C__Internal

#include "i2c_interface.h"
#include "i2c.h"
#include "uart.h"
#include "evhdl_iterface.h"

static void I2C_ISR_handler(uint8 channel);

/* Globals to be shared throughout the project */
I2C_BUFFER i2c_tx_buffer;
I2C_BUFFER i2c_rx_buffer;

I2C__tstDevData I2C__Device[I2C_enNumOfDevices];

/* Globals for this file only */
uint8 master_mode = 0;
uint8 iic_mode = 0;
uint8 master_tx_done;
uint8 rev_flg = 0;

I2C__tstGlobalData I2C__stMdata;

extern uint8 I2C__DeviceModuel[I2C_enNumOfDevices];
extern uint8 I2C__DeviceAddr[I2C_enNumOfDevices];

const uint16 i2c_prescaler_val[] = 
{    
    20,40,80,
    22,44,88,
    24,48,96,
    26,52,108,
    28,56,112,
    30,60,120,
    34,68,136,
    40,80,160,
    28,56,112,
    32,64,128,
    36,72,144,
    40,80,160,
    44,88,176,
    48,96,192,
    56,112,224,
    68,136,272,
    48,96,192,
    56,112,224,
    64,128,256,
    72,144,288,
    80,160,320,
    88,176,352,
    104,208,416,
    128,256,512,
    80,160,320,
    96,192,384,
    112,224,448,
    128,256,512,
    144,288,576,
    160,320,640,
    192,384,768,
    240,480,960,
    160,320,640,
    192,384,768,
    224,448,896,
    256,512,1024,
    288,576,1152,
    320,640,1280,
    384,768,1536,
    480,960,1920,
    320,640,1280,
    384,768,1536,
    448,896,1792,
    512,1024,2048,
    576,1152,2304,
    640,1280,2560,
    768,1536,3072,
    960,1920,3840,
    640,1280,2560,
    768,1536,3072,
    896,1792,3584,
    1024,2048,4096,
    1152,2304,4608,
    1280,2560,5120,
    1536,3072,6144,
    1920,3840,7680,
    1280,2560,5120,
    1536,3072,6144,
    1792,3584,7168,
    2048,4096,8192,
    2304,4608,9216,
    2560,5120,10240,
    3072,6144,12288,
    3840,7680,15360,
};




/*
Function i2c_set_bps
Description : set baud of i2c module
*/
static int _i2c_set_bps(uint8 channel, uint32 bps)
{
  uint8 x;
  uint8 best_ndx=(uint8)-1u;
  uint8 best_mul=(uint8)-1u;
  uint16 e=(uint16)-1u;
  uint32 d=(BUS_CLOCK)/bps;
  
  for(x=0; x<sizeof(i2c_prescaler_val)/sizeof(i2c_prescaler_val[0]); x++)
  {
    uint16 e1;
    if (d>i2c_prescaler_val[x])
    {
      continue;
    }
    
    e1=(unsigned short)(i2c_prescaler_val[x]-d);
    if ((e1<e) || (e1==0))
    {
      e=e1;
      best_ndx=x/3;
      best_mul=x%3;
    }
  }

  if (best_ndx == (uint8)-1u)
  {
    return(-1);
  } 
  I2C_F(channel) = (best_mul<<I2C_F_MULT_SHIFT) + best_ndx;
  return(0);
}

static int _i2c_init_pin_mux(uint8 channel)
{
	/* Configure GPIO pins to I2C function */
	switch (channel)
	{
	case 0:
		I2C__SCL0_PCR = PORT_PCR_MUX(I2C__SCL0_MUX) | PORT_PCR_DSE_MASK;
		I2C__SDA0_PCR = PORT_PCR_MUX(I2C__SDA0_MUX) | PORT_PCR_DSE_MASK;
		break;
	case 1:
		I2C__SCL1_PCR = PORT_PCR_MUX(I2C__SCL1_MUX) | PORT_PCR_DSE_MASK;
		I2C__SDA1_PCR = PORT_PCR_MUX(I2C__SDA1_MUX) | PORT_PCR_DSE_MASK;
		break;
	default:
		return -1;
	}
	return 0;
}

void i2c_init(uint8 channel, uint8 addr, uint32 bps)
{

	if (_i2c_init_pin_mux(channel) == -1)
	{
		printf("***Fail in i2c pin mux config***\r\n");
		return;
	}
	if (-1 == _i2c_set_bps(channel, bps))
	{
		printf("***Fail in i2c set bps***\r\n");
		return;
	}

	I2C_C2(channel) = 0x0; //general call disabled, 7-bit address

#if POLLING_MODE
	I2C_C1(channel) = I2C_C1_IICEN_MASK | 0;
#else	
	/* start the module and enable interrupt */I2C_C1(channel) =
			I2C_C1_IICEN_MASK | I2C_C1_IICIE_MASK | 0;
#endif	
	/* set slave address */I2C_A1(channel) = addr << 1;

	/* initial RAM variable */
	iic_mode = 0;
}


/********************************************************************

**********/
/*	Purpose:  	General function for performing I2C master transfers.  Capable
 *				of performing Master TX, Master RX, and Master TX/RX w/ Repeated
 *				Start.
 *				
 *	Arguments:	mode - Valid modes include I2C_TX, I2C_RX, and I2C_TXRX 
 *					(all modes defined in i2c.h)
 *				slave_address - The slave address of the I2C module that needs
 *					to be dealt with.  
 */
void i2c_master (uint8 channel, uint8 mode, uint16 slave_address)
{
	/* Interrrupt-Driven */
    
	master_mode = mode;
	if(master_mode>I2C_TXRX)
	    master_mode -= I2C_10BIT_TX;//10 bit address mode  
	master_tx_done = FALSE;
	
	/* Reset index for TX and RX buffers */
	i2c_tx_buffer.tx_index = 0;
	i2c_rx_buffer.rx_index = 0;
    
    /* Transmit followed by receive using RSTA */
    if (mode == I2C_TXRX)
    {
    	/* Make sure bus is idle */
    	while (I2C_S(channel) & I2C_S_BUSY_MASK);
    	/* Put module in master TX mode (generates START) */
    	I2C_C1(channel) |= (I2C_C1_MST_MASK | I2C_C1_TX_MASK);
    	/* Put target address into IBDR */
    	I2C_D(channel) = ( 0 | (slave_address << 1) | I2C_TX);
    	/* Wait for I2SR[IBB] (bus busy) to be set */
    	while (!(I2C_S(channel) & I2C_S_BUSY_MASK));

    	/* Wait for TX to finish before starting RX */
    	while (!master_tx_done);
    	
    	master_mode = I2C_RX;
    	/* Set IBCR.RSTA and put in master RX mode */
    	I2C_C1(channel) |= (0 | I2C_C1_RSTA_MASK);
    	/* Put target address into IBDR and set the R/!W bit */
    	I2C_D(channel) = (0 | (slave_address << 1) | I2C_RX);
    	
    	/* Wait for bus to become free before continuing */
    	while (I2C_S(channel) & I2C_S_BUSY_MASK);
    	
    	/* Restore module to it's idle (but active) state */
    	I2C_C1(channel) = 0xC0;
    	
    	return;
    }
    /* Single TX or RX */
    else if ( (mode == I2C_TX) || (mode == I2C_RX) )
    {
    	/* Make sure bus is idle */
    	while (I2C_S(channel) & I2C_S_BUSY_MASK);
    	/* Put module in master TX mode (generates START) */
    	I2C_C1(channel) |= (0 | I2C_C1_MST_MASK | I2C_C1_TX_MASK);
    	/* Put target address into IBDR */
    	I2C_D(channel) = ( 0 | (slave_address << 1) | mode);
    	/* Wait for I2SR[IBB] (bus busy) to be set */
    	while (!(I2C_S(channel) & I2C_S_BUSY_MASK));
    	
    	/* Wait for bus to become free before continuing */
    	while (I2C_S(channel) & I2C_S_BUSY_MASK);

    	/* Restore module to it's idle (but active) state */
    	I2C_C1(channel) = 0xC0;
    	
    	return;
    }
    else{
	  /*do nothing*/
    }
}

void I2C_StartJob (uint8 u8Channel, uint8 u8Job, uint16 u16Slave_Addr)
{
	I2C__stMdata.u8Master_mode = u8Job;
	//I2C__stMdata.bTX_done = FALSE;	
	if (I2C_TXRX == I2C__stMdata.u8Master_mode)
	{
		/* Make sure bus is idle */
		while (I2C_S(u8Channel) & I2C_S_BUSY_MASK);
		/* Put module in master TX mode (generates START) */
		I2C_C1(u8Channel) |=
				(I2C_C1_MST_MASK | I2C_C1_TX_MASK);
		/* Put target address into IBDR */
		I2C_D(u8Channel) = 
				(0 | (u16Slave_Addr << 1) | I2C_TX);
		/* Wait for I2SR[IBB] (bus busy) to be set */
		while (!(I2C_S(u8Channel) & I2C_S_BUSY_MASK));
	}
	/* Single TX or RX */
    else if (I2C_TX == I2C__stMdata.u8Master_mode)
	{
		/* Make sure bus is idle */
		while (I2C_S(u8Channel) & I2C_S_BUSY_MASK);
		/* Put module in master TX mode (generates START) */
		I2C_C1(u8Channel) |=
				(0 | I2C_C1_MST_MASK | I2C_C1_TX_MASK);
		/* Put target address into IBDR */
		I2C_D(u8Channel) = (0
				| (u16Slave_Addr << 1) | u8Job);
		/* Wait for I2SR[IBB] (bus busy) to be set */
		while (!(I2C_S(u8Channel) & I2C_S_BUSY_MASK));
		
		/*FixMe: This part is not working so it is commented */
		/* Wait for bus to become free before continuing */
		//while (I2C_S(u8Channel) & I2C_S_BUSY_MASK);

		/* Restore module to it's idle (but active) state */
		//I2C_C1(u8Channel) = 0xC0;
	}
	else
    {
    	/*Do nothing*/
    }
}

void I2C__TxFinish(uint8 u8Channel)
{
   uint8 x = 0;
   uint8 u8CurrDevice = 0;
   for (x = 0; x < I2C_enNumOfDevices; x++)
   {
      if (I2C__Device[x].bActive)
      {
         u8CurrDevice = x;
      }
      else
      {
         /*Do nothing*/
      }
   }

   if (I2C__stMdata.u8Master_mode == I2C_TXRX)
   {
      I2C__stMdata.u8Master_mode = I2C_RX;
      /* Set IBCR.RSTA and put in master RX mode */
      I2C_C1(u8Channel) |= (0 | I2C_C1_RSTA_MASK);
      /* Put target address into IBDR and set the R/!W bit */
      I2C_D(u8Channel) = (0 | (I2C__Device[u8CurrDevice].u8SlaveAddr << 1) | I2C_RX);
      /* Wait for bus to become free before continuing */
      while (I2C_S(u8Channel) & I2C_S_BUSY_MASK);
      /* Restore module to it's idle (but active) state */
      I2C_C1(u8Channel) = 0xC0;
   }
   else
   {
      /* Generate STOP signal */
      I2C_C1(u8Channel) &= ~I2C_C1_MST_MASK;
      I2C__Device[u8CurrDevice].bActive = False;
      /*Call the event handler function of the Application */
      if (NULL != I2C__Device[u8CurrDevice].DeviceEvent)
      {
         I2C__Device[u8CurrDevice].DeviceEvent(I2C_nTXEvent);
      }
   }
}

void I2C__RxFinish(uint8 u8Channel)
{
   uint8 x,y = 0;
   //uint8 *u8bAppBuff = &I2C__Device[u8CurrDevice].u8pAppBuffPtr;
   for (x = 0; x < I2C_enNumOfDevices; x++)
   {
      if (I2C__Device[x].bActive)
      {        
         /*Set device active flag as false */
         I2C__Device[x].bActive = False;

         /* Copy data to application buffer */
         for (y = 0; y < I2C__Device[x].u8RxCopylength; y++)
         {
            I2C__Device[x].u8pAppBuffPtr[y] = I2C__Device[x].u8RxBuff[y];
         }
         
         /*Call the event handler function of the Application */
         if (NULL != I2C__Device[x].DeviceEvent)
         {
            I2C__Device[x].DeviceEvent(I2C_nRXEvent);
         }
      }
      else
      {
         /*Do nothing*/
      }
   }

}



void I2C0_IRQHandler(void)
{
	/* Typicall I2C interrupt routine */
	I2C_ISR_handler(0); 
	//i2c_handler(0); 
}

void I2C1_IRQHandler(void)
{
	/* Typicall I2C interrupt routine */
	i2c_handler(1); 
}


/******************************************************************************/
/*	Purpose:  	General I2C handler, created using the flowchart example 
 *				included in the I2C chapter of the UM.  
 */
static void i2c_handler(uint8 channel)
{
   }



static void I2C_ISR_handler(uint8 channel)
{
   /* Temp variable for dummy reads */
   uint8 x = 0;
   uint8 u8CurrDevice = 0;

   /*Select the active device*/

   for (x = 0; x < I2C_enNumOfDevices; x++)
   {
      if (I2C__Device[x].bActive)
      {
         u8CurrDevice = x;
      }
      else
      {
         /*Do nothing*/
      }
   }

   /* Clear the I2C Interrupt Flag. */I2C_S(channel) |= I2C_S_IICIF_MASK;

   /* Check if this device is in Master or Slave Mode. */
   if (I2C_C1(channel) & I2C_C1_MST_MASK)
   {
      /* Master Mode - Check if this device is in Transmit or Receive Mode. */
      if (I2C_C1(channel) & I2C_C1_TX_MASK)
      {
         I2C__vMasterTxHandling(u8CurrDevice, channel);
      }
      /*Master Receive Mode */
      else
      {
         I2C__vMasterRxHandling(u8CurrDevice, channel);
      }
   }
   else
   {
      /* Slave Mode - Check if Arbitration Lost. */
      if (I2C_S(channel) & I2C_S_ARBL_MASK)
      {

      }
      else
      {

      }
   }
}

inline void I2C__vMasterTxHandling(uint8 u8CurrDevice, uint8 channel)
{
   //uint8 dummy_read;

   /* Master Transmit Mode - Check if last byte was tranmitted. */
   if ((I2C__Device[u8CurrDevice].u8Txlength == 0) && (I2C__stMdata.u8Master_mode != I2C_RX))
   {
      /* Last byte was transmitted - 
         Send and event to stop transmission or start Rx
         and inform the app. */
      if (I2C__nChannel0 == channel)
      {
         EVHD_vSendEvent(EV_I2C_Chann0_TxFinish_Event);
      }
      else
      {
         EVHD_vSendEvent(EV_I2C_Chann1_TxFinish_Event);
      }
   }
   else
   {
      /* More bytes to be transmitted - Check if ACK received. */
      if (I2C_S(channel) & I2C_S_RXAK_MASK)
      {
         /* ACK not received - Generate STOP */
         I2C_C1(channel) &= ~I2C_C1_MST_MASK;

      }
      else
      {
         /* Check if end of address cycle */
         if (I2C__stMdata.u8Master_mode == I2C_RX)
         {
            I2C_C1(channel) &= ~I2C_C1_TX_MASK;

            /* there is only 1 byte to be received */
            if (I2C__Device[u8CurrDevice].u8Rxlength == 1)
            {
               I2C_C1(channel) |= I2C_C1_TXAK_MASK;
            }
            /*dummy read */
            (void)I2C_D(channel);
         }
         /* ACK received, send data */
         else
         {
            /* Not end of address cycle - Write next byte to MBDR */
            I2C_D(channel) = I2C__Device[u8CurrDevice].u8TxBuff[I2C__Device[u8CurrDevice].u8Tx_index++];
            I2C__Device[u8CurrDevice].u8Txlength--;

         }
      }
   }

}

inline void I2C__vMasterRxHandling(uint8 u8CurrDevice, uint8 channel)
{

   /* Master Receive Mode - Check if this is last byte to be read. */
   if (I2C__Device[u8CurrDevice].u8Rxlength == 1)
   {
      /* Last byte to be read - 
       Generate Stop signal by changing to Slave Mode. */
      I2C_C1(channel) &= ~I2C_C1_MST_MASK;
      
      /*Inform to app that the job is done */
      if (I2C__nChannel0 == channel)
      {
         EVHD_vSendEvent(EV_I2C_Chann0_RxFinish_Event);
      }
      else
      {
         EVHD_vSendEvent(EV_I2C_Chann1_RxFinish_Event);
      }
   }
   else
   {
      /* Not last byte to be read - Check if second to last byte. */
      if (I2C__Device[u8CurrDevice].u8Rxlength == 2)
      {
         /* Second to last byte to be read - Set Transmit Acknowledge Enable
          bit so no ACK is sent after the next byte is received, which
          indicates "end of data" to the slave. */
         I2C_C1(channel) |= I2C_C1_TXAK_MASK;

      }
   }

   /* Store received data in RX buffer */
   I2C__Device[u8CurrDevice].u8RxBuff[I2C__Device[u8CurrDevice].u8Rx_index++] = I2C_D(channel);
   I2C__Device[u8CurrDevice].u8Rxlength--;

}


